Summary¶
1. How accessible is charging infrastructure for electric vehicles across different regions in Washington State?
Public charging stations and infrastructure are very accessible to electric vehicle owners in urban areas, while more rural areas like Eastern Washington have a lack of publicly available charging stations.
2. Are there areas with a higher concentration of electric vehicles but limited charging infrastructure?
Most definitely. Almost the entire eastern side of Washington state along with areas near the Oregon border and near the Washington coast seem to have a lower concentration of charging stations.
3. Is there a racial disparity in access to electric vehicles in Washington state?
There seems to be. In areas with higher white populations, there is higher EV ownership. In areas with higher populations of POC, EV ownership is lower.
4. Can we identify clusters or hotspots of electric vehicle adoption in specific urban or rural areas?
There seems to be a pattern of electric vehicle adoption in urban areas where there is a higher concentration of people living together. However, viewing the map of electric vehicles, you can see that the rest of Washington has electric vehicles dispersed throughout the state in differing regions.
Motivation¶
As informed by Fuel Economy (.gov), gas-powered vehicles release about 1.5 billion tons of greenhouse gas emissions into the atmosphere each year. With the rapid manufacturing, production, and selling of electric vehicles, along with growing government policies promoting and potentially transitioning our society to the use of electric vehicles over gas-powered vehicles, we find this topic to be very relevant. Many hail electric vehicles as one of the most important ways individuals as consumers can contribute to reducing greenhouse gas emissions, yet access to these electric vehicles is often a socioeconomic privilege. We are curious as to how race can affect access to electric vehicles. Additionally, we are interested in how accessible charging stations are and if there are areas where there is a lack of charging infrastructure.
Data Setting¶
Electric Vehicle Population Dataset URL: https://catalog.data.gov/dataset/electric-vehicle-population-data
This dataset shows the Battery Electric Vehicles (BEVs) and Plug-in Hybrid Electric Vehicles (PHEVs) that are currently registered through the Washington State Department of Licensing (DoL). This dataset is continually updated, so the data for EVs in Washington is present-day.
EV Charging Station Location Dataset URL: https://afdc.energy.gov/fuels/electricity_locations.html#/find/nearest?location=WA
This is one of two extra datasets we are including to meet a challenge goal. This dataset consists of EV charging stations and their corresponding location (coordinates, city, zip code) along with some other information on the chargers that we may not use, depending on insights and finding answers to our research questions. Some unimportant columns for using this dataset in our context would be columns like payment type, station phone number, and owners, to name a few.
2010 Census Race Data by Legislative District URL: https://data.wa.gov/Demographics/WAOFM-Legislative-Districts-Table-2-Census-2010-Po/di4y-k8za/about_data
By including this extra dataset, we are able to meet one of our challenge goals. It includes racial demographic data from the 2010 census in Washington, organized by Legislative District. The reason this dataset is being used is that the electric vehicle data also includes what legislative district the vehicle is registered in, so this will be a useful column to merge on later for comparison. Since this is census data that only focuses on a specific year, it may be hard to draw many meaningful conclusions, especially when the times when data was collected do not match between the EV data and this dataset, but I still think it will be interesting to compare legislative district racial demographics with EV ownership in the area.
Method¶
2010 Census Race + EV dataset methods¶
- Load in the racial demographics and EV datasets.
- Clean the datasets by dropping NA rows, and making sure that column types are the same for merging.
- Calculate the percentage EV ownership and racial distributions.
- Merge the datasets into a data frame by the column
Legislative District. - Use plotly express to create an interactive scatterplot showing the relationship between the percentage of white individuals to the percentage of EV ownership per legislative district.
- Use seaborn to create a barplot representing the racial demographics of the legislative districts with the highest and lowest EV ownership.
Charging station + EV dataset methods¶
- Load in the charging stations dataset and the EV dataset.
- For the charging station dataset, the columns latitude and longitude are provided, which signal a location. However, this is not a format that geopandas can identify. Therefore, we need to create a geometry column, using geopandas to combine latitude and longitude.
- Develop map visualizations for EV locations relative to charging stations using geopandas.
- Also, develop map visualization for EV locations based on Legislative District relative to charging stations.
- Use a new library such as folium or plotly to achieve our second challenge goal, to make the map interactive. One example of how to make this map interactive would be the ability to hold your cursor over a specific point, and it would give data on the location of either an electric vehicle or a charging station.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
!pip install plotly
import plotly.express as px
import numpy as np
import geopandas as gpd
from shapely import wkt
from shapely.geometry import Point
!pip install -q folium mapclassify
!pip install -q plotly
import folium
from folium.plugins import MarkerCluster
from IPython.display import display
from IPython.display import HTML
Requirement already satisfied: plotly in /opt/conda/lib/python3.10/site-packages (5.19.0) Requirement already satisfied: tenacity>=6.2.0 in /opt/conda/lib/python3.10/site-packages (from plotly) (8.2.3) Requirement already satisfied: packaging in /opt/conda/lib/python3.10/site-packages (from plotly) (23.2)
"""Imports the WA Electric Vehicle and 2010 Census Race Data by Legislative District datasets"""
# Read in EV dataset
ev = pd.read_csv('ev.csv')
# Read in census data
leg = pd.read_csv('legislative.csv')
dirty_charging_df = pd.read_csv("EV_Charging_Stations.csv")
clean_charging_df = dirty_charging_df[['Fuel Type Code', 'Station Name', 'Street Address',
'City', 'State', 'ZIP', 'Station Phone', 'Groups With Access Code',
'Access Days Time', 'EV Network', 'Geocode Status',
'Latitude', 'Longitude', 'Date Last Confirmed',
'ID', 'Updated At', 'EV Connector Types', 'Country',
'Access Code', 'EV Workplace Charging']]
ev_df = pd.read_csv("Clean_EV_Population.csv")
charging_df = pd.read_csv("Clean_EV_Charging_Stations.csv")
racial_df = pd.read_csv("Clean_Legislative.csv")
state_data = gpd.read_file("tl_2010_53_tract00.shp")
charging_df['geometry'] = [Point(xy) for xy in zip(charging_df.Longitude, charging_df.Latitude)]
racial_df['Legislative District'] = pd.to_numeric(racial_df['Legislative District'], errors='coerce')
"""Cleans the EV dataset"""
# Dropping NA values in the Vehicle Location and Legislative District columns
ev.dropna(subset=['Vehicle Location', 'Legislative District'], inplace=True)
# Legislative District column in EV dataset was a float type. This converts the column to a string type
ev['Legislative District'] = ev['Legislative District'].astype(int)
ev['Legislative District'] = ev['Legislative District'].astype(str)
"""Percent EV ownership per legislative district"""
# Counts the number of electric vehicles in each legislative district, then calculates the sum of all the EVs
# in the data set
evs_per_district = ev.groupby('Legislative District').size()
total_evs = evs_per_district.sum()
# Calulcating the percentage of EVs per district out of all EVs in the state, rounding to 2 decimal points
rates = (evs_per_district / total_evs) * 100
rates = rates.round(2)
# Resets the index to aid in merging the two data frames
rates = rates.reset_index()
rates.columns = ['Legislative District', 'Percentage EV Ownership']
# Having an issue with the merge function creating duplicate 'Percentage EV Ownership' columns when
# the cell was run multiple times. This drops the column in the EV dataset to avoid this issue.
if 'Percentage EV Ownership' in ev:
ev.drop(columns='Percentage EV Ownership', inplace=True)
ev = pd.merge(ev, rates, on='Legislative District', how='left')
# Testing the Percentage EV Ownership calculations on a small subset of the dataframe
rates_subset = rates[rates['Legislative District'].isin(['5', '6', '7', '8', '9'])]
rates_subset = rates_subset.reset_index(drop=True)
expected_output1 = pd.DataFrame({'Legislative District': ['5', '6', '7', '8', '9'], 'Percentage EV Ownership': [4.24, 0.96, 0.47, 1.04, 0.56]})
assert rates_subset.equals(expected_output1), 'Test failed'
print('Test passed')
ev
Test passed
| VIN (1-10) | County | City | State | Postal Code | Model Year | Make | Model | Electric Vehicle Type | Clean Alternative Fuel Vehicle (CAFV) Eligibility | Electric Range | Base MSRP | Legislative District | DOL Vehicle ID | Vehicle Location | Electric Utility | 2020 Census Tract | Percentage EV Ownership | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 3C3CFFGE4E | Yakima | Yakima | WA | 98902.0 | 2014 | FIAT | 500 | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | 87 | 0 | 14 | 1593721 | POINT (-120.524012 46.5973939) | PACIFICORP | 5.307700e+10 | 0.65 |
| 1 | 5YJXCBE40H | Thurston | Olympia | WA | 98513.0 | 2017 | TESLA | MODEL X | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | 200 | 0 | 2 | 257167501 | POINT (-122.817545 46.98876) | PUGET SOUND ENERGY INC | 5.306701e+10 | 1.13 |
| 2 | 3MW39FS03P | King | Renton | WA | 98058.0 | 2023 | BMW | 330E | Plug-in Hybrid Electric Vehicle (PHEV) | Not eligible due to low battery range | 20 | 0 | 11 | 224071816 | POINT (-122.1298876 47.4451257) | PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA) | 5.303303e+10 | 3.97 |
| 3 | 7PDSGABA8P | Snohomish | Bothell | WA | 98012.0 | 2023 | RIVIAN | R1S | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | 0 | 0 | 21 | 260084653 | POINT (-122.1873 47.820245) | PUGET SOUND ENERGY INC | 5.306105e+10 | 2.50 |
| 4 | 5YJ3E1EB8L | King | Kent | WA | 98031.0 | 2020 | TESLA | MODEL 3 | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | 322 | 0 | 33 | 253771913 | POINT (-122.2012521 47.3931814) | PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA) | 5.303303e+10 | 2.03 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 166430 | 3FA6P0SU4D | Spokane | Spokane | WA | 99223.0 | 2013 | FORD | FUSION | Plug-in Hybrid Electric Vehicle (PHEV) | Not eligible due to low battery range | 19 | 0 | 6 | 239527123 | POINT (-117.369705 47.62637) | BONNEVILLE POWER ADMINISTRATION||AVISTA CORP||... | 5.306300e+10 | 0.96 |
| 166431 | 5YJYGDEE5M | King | Sammamish | WA | 98074.0 | 2021 | TESLA | MODEL Y | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | 0 | 0 | 45 | 148715479 | POINT (-122.0313266 47.6285782) | PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA) | 5.303303e+10 | 6.05 |
| 166432 | 7SAYGDEE5N | Snohomish | Mukilteo | WA | 98275.0 | 2022 | TESLA | MODEL Y | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | 0 | 0 | 21 | 220504406 | POINT (-122.299965 47.94171) | PUGET SOUND ENERGY INC | 5.306104e+10 | 2.50 |
| 166433 | 1G1RH6E43D | Lewis | Mossyrock | WA | 98564.0 | 2013 | CHEVROLET | VOLT | Plug-in Hybrid Electric Vehicle (PHEV) | Clean Alternative Fuel Vehicle Eligible | 38 | 0 | 20 | 156418475 | POINT (-122.487535 46.5290135) | BONNEVILLE POWER ADMINISTRATION||CITY OF TACOM... | 5.304197e+10 | 0.90 |
| 166434 | 5YJSA1E27H | Pierce | Gig Harbor | WA | 98332.0 | 2017 | TESLA | MODEL S | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | 210 | 0 | 26 | 169045789 | POINT (-122.589645 47.342345) | BONNEVILLE POWER ADMINISTRATION||CITY OF TACOM... | 5.305307e+10 | 2.00 |
166435 rows × 18 columns
"""Cleaning Legislative District dataset"""
# Removing the 0 in front of the single digit legislative districts, then making a copy of the data frame with only certain columns
leg['Legislative District'] = leg['Legislative District'].str.lstrip('0')
subset = leg[['Legislative District', 'Total Population 2010', 'White Alone 2010', 'Black or African American Alone 2010',
'American Indian and Alaska Native Alone 2010', 'Asian Alone 2010', 'Native Hawaiian and Other Pacific Islander Alone 2010',
'Some Other Race Alone 2010', 'Population of Two or More Races 2010']].copy()
subset
| Legislative District | Total Population 2010 | White Alone 2010 | Black or African American Alone 2010 | American Indian and Alaska Native Alone 2010 | Asian Alone 2010 | Native Hawaiian and Other Pacific Islander Alone 2010 | Some Other Race Alone 2010 | Population of Two or More Races 2010 | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | Washington State | 6724540 | 5196362 | 240042 | 103869 | 481067 | 40475 | 349799 | 312926 |
| 1 | 10 | 137233 | 119541 | 2004 | 1948 | 4275 | 513 | 3870 | 5082 |
| 2 | 11 | 137278 | 71456 | 15773 | 1122 | 30275 | 1384 | 9082 | 8186 |
| 3 | 12 | 137285 | 107156 | 467 | 4599 | 990 | 175 | 20029 | 3869 |
| 4 | 13 | 137280 | 108807 | 1344 | 1434 | 1640 | 131 | 19459 | 4465 |
| 5 | 14 | 137218 | 101108 | 1410 | 6702 | 1792 | 133 | 20918 | 5155 |
| 6 | 15 | 137224 | 81973 | 1047 | 4541 | 1011 | 106 | 43623 | 4923 |
| 7 | 16 | 137198 | 99538 | 1966 | 1241 | 1484 | 257 | 28740 | 3972 |
| 8 | 17 | 137230 | 114836 | 3088 | 1160 | 6967 | 1195 | 3936 | 6048 |
| 9 | 18 | 137217 | 122591 | 1255 | 947 | 5725 | 354 | 1769 | 4576 |
| 10 | 19 | 137232 | 119320 | 1196 | 3164 | 2303 | 320 | 5632 | 5297 |
| 11 | 20 | 137204 | 123839 | 772 | 1929 | 1202 | 239 | 4704 | 4519 |
| 12 | 21 | 137260 | 97656 | 5213 | 1159 | 19384 | 782 | 6187 | 6879 |
| 13 | 22 | 137239 | 111921 | 4016 | 1494 | 8589 | 1115 | 2601 | 7503 |
| 14 | 23 | 137217 | 111882 | 3350 | 2521 | 8193 | 1106 | 2193 | 7972 |
| 15 | 24 | 137280 | 120267 | 1058 | 6218 | 1920 | 221 | 2481 | 5115 |
| 16 | 25 | 137235 | 106168 | 6047 | 2074 | 8050 | 1646 | 4765 | 8485 |
| 17 | 26 | 137274 | 118577 | 3038 | 1568 | 4438 | 1093 | 1733 | 6827 |
| 18 | 27 | 137224 | 93814 | 13627 | 2726 | 10136 | 1254 | 5407 | 10260 |
| 19 | 28 | 137216 | 98047 | 11895 | 1416 | 9357 | 1924 | 3598 | 10979 |
| 20 | 29 | 137257 | 78163 | 17608 | 2035 | 12565 | 4404 | 9652 | 12830 |
| 21 | 30 | 137261 | 86079 | 10944 | 1494 | 16655 | 3064 | 10428 | 8597 |
| 22 | 31 | 137214 | 117744 | 2072 | 3064 | 4177 | 715 | 3812 | 5630 |
| 23 | 32 | 137225 | 96732 | 7011 | 1236 | 19614 | 581 | 5090 | 6961 |
| 24 | 33 | 137237 | 76183 | 15672 | 1769 | 18059 | 3563 | 13675 | 8316 |
| 25 | 34 | 137208 | 96382 | 8523 | 1557 | 14499 | 1214 | 7648 | 7385 |
| 26 | 35 | 137219 | 119040 | 2032 | 3147 | 3220 | 638 | 3163 | 5979 |
| 27 | 36 | 137247 | 114573 | 3725 | 1007 | 9529 | 298 | 2052 | 6063 |
| 28 | 37 | 137192 | 54545 | 31408 | 1174 | 36167 | 903 | 4957 | 8038 |
| 29 | 38 | 137242 | 105267 | 4140 | 4619 | 8138 | 839 | 7044 | 7195 |
| 30 | 39 | 137201 | 120439 | 1414 | 1982 | 2704 | 353 | 5493 | 4816 |
| 31 | 40 | 137259 | 117134 | 1303 | 1533 | 3807 | 255 | 8129 | 5098 |
| 32 | 41 | 137250 | 95315 | 2559 | 402 | 30936 | 269 | 2270 | 5499 |
| 33 | 42 | 137231 | 115238 | 1195 | 5107 | 4798 | 367 | 5573 | 4953 |
| 34 | 43 | 137252 | 107212 | 4961 | 860 | 15187 | 290 | 2058 | 6684 |
| 35 | 44 | 137246 | 112605 | 2308 | 1070 | 11220 | 456 | 3301 | 6286 |
| 36 | 45 | 137281 | 108934 | 1660 | 527 | 17449 | 206 | 2970 | 5535 |
| 37 | 46 | 137253 | 104001 | 5446 | 934 | 16449 | 414 | 2899 | 7110 |
| 38 | 47 | 137210 | 90810 | 9587 | 1103 | 19594 | 1637 | 6625 | 7854 |
| 39 | 48 | 137226 | 91704 | 2784 | 543 | 32355 | 261 | 4229 | 5350 |
| 40 | 49 | 137244 | 113137 | 3995 | 1370 | 4707 | 1142 | 6630 | 6263 |
| 41 | 1 | 137236 | 108239 | 2426 | 865 | 15785 | 417 | 3564 | 5940 |
| 42 | 2 | 137202 | 110085 | 4987 | 2254 | 5768 | 1532 | 3762 | 8814 |
| 43 | 3 | 137226 | 116887 | 3756 | 3294 | 3436 | 810 | 2036 | 7007 |
| 44 | 4 | 137281 | 126031 | 1273 | 1485 | 2366 | 298 | 1636 | 4192 |
| 45 | 5 | 137210 | 116500 | 1567 | 865 | 10306 | 275 | 2330 | 5367 |
| 46 | 6 | 137198 | 121721 | 2681 | 1840 | 3479 | 694 | 1784 | 4999 |
| 47 | 7 | 137263 | 121820 | 647 | 6208 | 1143 | 199 | 2746 | 4500 |
| 48 | 8 | 137202 | 113603 | 2047 | 1200 | 4323 | 223 | 10628 | 5178 |
| 49 | 9 | 137223 | 111742 | 1745 | 1362 | 4901 | 210 | 12888 | 4375 |
"""Legislative District racial distributions"""
# Selects the race columns in the subset dataframe and creates a new column for each race that calculates the percent of that race out
# of the total population in each legislative district. Rounds the percent to two decimal points
for column in subset.columns[2:9]:
subset.loc[:, column + ' Percentage'] = (subset[column] / subset['Total Population 2010']) * 100
subset = subset.round(2)
# Testing the race percentage calculations on a small subset of the dataframe
subset_test = subset[subset['Legislative District'].isin(['10', '11', '12', '13', '14'])]
columns = ['Legislative District', 'White Alone 2010 Percentage', 'Black or African American Alone 2010 Percentage',
'American Indian and Alaska Native Alone 2010 Percentage', 'Asian Alone 2010 Percentage',
'Native Hawaiian and Other Pacific Islander Alone 2010 Percentage', 'Some Other Race Alone 2010 Percentage',
'Population of Two or More Races 2010 Percentage']
subset_test = subset_test.reset_index(drop=True)
expected_output2 = pd.DataFrame({'Legislative District': ['10', '11', '12', '13', '14'], 'White Alone 2010 Percentage': [87.11, 52.05, 78.05, 79.26, 73.68],
'Black or African American Alone 2010 Percentage': [1.46, 11.49, 0.34, 0.98, 1.03],
'American Indian and Alaska Native Alone 2010 Percentage': [1.42, 0.82, 3.35, 1.04, 4.88],
'Asian Alone 2010 Percentage': [3.12, 22.05, 0.72, 1.19, 1.31],
'Native Hawaiian and Other Pacific Islander Alone 2010 Percentage': [0.37, 1.01, 0.13, 0.10, 0.10],
'Some Other Race Alone 2010 Percentage': [2.82, 6.62, 14.59, 14.17, 15.24],
'Population of Two or More Races 2010 Percentage': [3.70, 5.96, 2.82, 3.25, 3.76]})
assert subset_test[columns].equals(expected_output2), 'Test failed'
print('Test passed')
subset
Test passed
| Legislative District | Total Population 2010 | White Alone 2010 | Black or African American Alone 2010 | American Indian and Alaska Native Alone 2010 | Asian Alone 2010 | Native Hawaiian and Other Pacific Islander Alone 2010 | Some Other Race Alone 2010 | Population of Two or More Races 2010 | White Alone 2010 Percentage | Black or African American Alone 2010 Percentage | American Indian and Alaska Native Alone 2010 Percentage | Asian Alone 2010 Percentage | Native Hawaiian and Other Pacific Islander Alone 2010 Percentage | Some Other Race Alone 2010 Percentage | Population of Two or More Races 2010 Percentage | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Washington State | 6724540 | 5196362 | 240042 | 103869 | 481067 | 40475 | 349799 | 312926 | 77.27 | 3.57 | 1.54 | 7.15 | 0.60 | 5.20 | 4.65 |
| 1 | 10 | 137233 | 119541 | 2004 | 1948 | 4275 | 513 | 3870 | 5082 | 87.11 | 1.46 | 1.42 | 3.12 | 0.37 | 2.82 | 3.70 |
| 2 | 11 | 137278 | 71456 | 15773 | 1122 | 30275 | 1384 | 9082 | 8186 | 52.05 | 11.49 | 0.82 | 22.05 | 1.01 | 6.62 | 5.96 |
| 3 | 12 | 137285 | 107156 | 467 | 4599 | 990 | 175 | 20029 | 3869 | 78.05 | 0.34 | 3.35 | 0.72 | 0.13 | 14.59 | 2.82 |
| 4 | 13 | 137280 | 108807 | 1344 | 1434 | 1640 | 131 | 19459 | 4465 | 79.26 | 0.98 | 1.04 | 1.19 | 0.10 | 14.17 | 3.25 |
| 5 | 14 | 137218 | 101108 | 1410 | 6702 | 1792 | 133 | 20918 | 5155 | 73.68 | 1.03 | 4.88 | 1.31 | 0.10 | 15.24 | 3.76 |
| 6 | 15 | 137224 | 81973 | 1047 | 4541 | 1011 | 106 | 43623 | 4923 | 59.74 | 0.76 | 3.31 | 0.74 | 0.08 | 31.79 | 3.59 |
| 7 | 16 | 137198 | 99538 | 1966 | 1241 | 1484 | 257 | 28740 | 3972 | 72.55 | 1.43 | 0.90 | 1.08 | 0.19 | 20.95 | 2.90 |
| 8 | 17 | 137230 | 114836 | 3088 | 1160 | 6967 | 1195 | 3936 | 6048 | 83.68 | 2.25 | 0.85 | 5.08 | 0.87 | 2.87 | 4.41 |
| 9 | 18 | 137217 | 122591 | 1255 | 947 | 5725 | 354 | 1769 | 4576 | 89.34 | 0.91 | 0.69 | 4.17 | 0.26 | 1.29 | 3.33 |
| 10 | 19 | 137232 | 119320 | 1196 | 3164 | 2303 | 320 | 5632 | 5297 | 86.95 | 0.87 | 2.31 | 1.68 | 0.23 | 4.10 | 3.86 |
| 11 | 20 | 137204 | 123839 | 772 | 1929 | 1202 | 239 | 4704 | 4519 | 90.26 | 0.56 | 1.41 | 0.88 | 0.17 | 3.43 | 3.29 |
| 12 | 21 | 137260 | 97656 | 5213 | 1159 | 19384 | 782 | 6187 | 6879 | 71.15 | 3.80 | 0.84 | 14.12 | 0.57 | 4.51 | 5.01 |
| 13 | 22 | 137239 | 111921 | 4016 | 1494 | 8589 | 1115 | 2601 | 7503 | 81.55 | 2.93 | 1.09 | 6.26 | 0.81 | 1.90 | 5.47 |
| 14 | 23 | 137217 | 111882 | 3350 | 2521 | 8193 | 1106 | 2193 | 7972 | 81.54 | 2.44 | 1.84 | 5.97 | 0.81 | 1.60 | 5.81 |
| 15 | 24 | 137280 | 120267 | 1058 | 6218 | 1920 | 221 | 2481 | 5115 | 87.61 | 0.77 | 4.53 | 1.40 | 0.16 | 1.81 | 3.73 |
| 16 | 25 | 137235 | 106168 | 6047 | 2074 | 8050 | 1646 | 4765 | 8485 | 77.36 | 4.41 | 1.51 | 5.87 | 1.20 | 3.47 | 6.18 |
| 17 | 26 | 137274 | 118577 | 3038 | 1568 | 4438 | 1093 | 1733 | 6827 | 86.38 | 2.21 | 1.14 | 3.23 | 0.80 | 1.26 | 4.97 |
| 18 | 27 | 137224 | 93814 | 13627 | 2726 | 10136 | 1254 | 5407 | 10260 | 68.37 | 9.93 | 1.99 | 7.39 | 0.91 | 3.94 | 7.48 |
| 19 | 28 | 137216 | 98047 | 11895 | 1416 | 9357 | 1924 | 3598 | 10979 | 71.45 | 8.67 | 1.03 | 6.82 | 1.40 | 2.62 | 8.00 |
| 20 | 29 | 137257 | 78163 | 17608 | 2035 | 12565 | 4404 | 9652 | 12830 | 56.95 | 12.83 | 1.48 | 9.15 | 3.21 | 7.03 | 9.35 |
| 21 | 30 | 137261 | 86079 | 10944 | 1494 | 16655 | 3064 | 10428 | 8597 | 62.71 | 7.97 | 1.09 | 12.13 | 2.23 | 7.60 | 6.26 |
| 22 | 31 | 137214 | 117744 | 2072 | 3064 | 4177 | 715 | 3812 | 5630 | 85.81 | 1.51 | 2.23 | 3.04 | 0.52 | 2.78 | 4.10 |
| 23 | 32 | 137225 | 96732 | 7011 | 1236 | 19614 | 581 | 5090 | 6961 | 70.49 | 5.11 | 0.90 | 14.29 | 0.42 | 3.71 | 5.07 |
| 24 | 33 | 137237 | 76183 | 15672 | 1769 | 18059 | 3563 | 13675 | 8316 | 55.51 | 11.42 | 1.29 | 13.16 | 2.60 | 9.96 | 6.06 |
| 25 | 34 | 137208 | 96382 | 8523 | 1557 | 14499 | 1214 | 7648 | 7385 | 70.25 | 6.21 | 1.13 | 10.57 | 0.88 | 5.57 | 5.38 |
| 26 | 35 | 137219 | 119040 | 2032 | 3147 | 3220 | 638 | 3163 | 5979 | 86.75 | 1.48 | 2.29 | 2.35 | 0.46 | 2.31 | 4.36 |
| 27 | 36 | 137247 | 114573 | 3725 | 1007 | 9529 | 298 | 2052 | 6063 | 83.48 | 2.71 | 0.73 | 6.94 | 0.22 | 1.50 | 4.42 |
| 28 | 37 | 137192 | 54545 | 31408 | 1174 | 36167 | 903 | 4957 | 8038 | 39.76 | 22.89 | 0.86 | 26.36 | 0.66 | 3.61 | 5.86 |
| 29 | 38 | 137242 | 105267 | 4140 | 4619 | 8138 | 839 | 7044 | 7195 | 76.70 | 3.02 | 3.37 | 5.93 | 0.61 | 5.13 | 5.24 |
| 30 | 39 | 137201 | 120439 | 1414 | 1982 | 2704 | 353 | 5493 | 4816 | 87.78 | 1.03 | 1.44 | 1.97 | 0.26 | 4.00 | 3.51 |
| 31 | 40 | 137259 | 117134 | 1303 | 1533 | 3807 | 255 | 8129 | 5098 | 85.34 | 0.95 | 1.12 | 2.77 | 0.19 | 5.92 | 3.71 |
| 32 | 41 | 137250 | 95315 | 2559 | 402 | 30936 | 269 | 2270 | 5499 | 69.45 | 1.86 | 0.29 | 22.54 | 0.20 | 1.65 | 4.01 |
| 33 | 42 | 137231 | 115238 | 1195 | 5107 | 4798 | 367 | 5573 | 4953 | 83.97 | 0.87 | 3.72 | 3.50 | 0.27 | 4.06 | 3.61 |
| 34 | 43 | 137252 | 107212 | 4961 | 860 | 15187 | 290 | 2058 | 6684 | 78.11 | 3.61 | 0.63 | 11.07 | 0.21 | 1.50 | 4.87 |
| 35 | 44 | 137246 | 112605 | 2308 | 1070 | 11220 | 456 | 3301 | 6286 | 82.05 | 1.68 | 0.78 | 8.18 | 0.33 | 2.41 | 4.58 |
| 36 | 45 | 137281 | 108934 | 1660 | 527 | 17449 | 206 | 2970 | 5535 | 79.35 | 1.21 | 0.38 | 12.71 | 0.15 | 2.16 | 4.03 |
| 37 | 46 | 137253 | 104001 | 5446 | 934 | 16449 | 414 | 2899 | 7110 | 75.77 | 3.97 | 0.68 | 11.98 | 0.30 | 2.11 | 5.18 |
| 38 | 47 | 137210 | 90810 | 9587 | 1103 | 19594 | 1637 | 6625 | 7854 | 66.18 | 6.99 | 0.80 | 14.28 | 1.19 | 4.83 | 5.72 |
| 39 | 48 | 137226 | 91704 | 2784 | 543 | 32355 | 261 | 4229 | 5350 | 66.83 | 2.03 | 0.40 | 23.58 | 0.19 | 3.08 | 3.90 |
| 40 | 49 | 137244 | 113137 | 3995 | 1370 | 4707 | 1142 | 6630 | 6263 | 82.43 | 2.91 | 1.00 | 3.43 | 0.83 | 4.83 | 4.56 |
| 41 | 1 | 137236 | 108239 | 2426 | 865 | 15785 | 417 | 3564 | 5940 | 78.87 | 1.77 | 0.63 | 11.50 | 0.30 | 2.60 | 4.33 |
| 42 | 2 | 137202 | 110085 | 4987 | 2254 | 5768 | 1532 | 3762 | 8814 | 80.24 | 3.63 | 1.64 | 4.20 | 1.12 | 2.74 | 6.42 |
| 43 | 3 | 137226 | 116887 | 3756 | 3294 | 3436 | 810 | 2036 | 7007 | 85.18 | 2.74 | 2.40 | 2.50 | 0.59 | 1.48 | 5.11 |
| 44 | 4 | 137281 | 126031 | 1273 | 1485 | 2366 | 298 | 1636 | 4192 | 91.81 | 0.93 | 1.08 | 1.72 | 0.22 | 1.19 | 3.05 |
| 45 | 5 | 137210 | 116500 | 1567 | 865 | 10306 | 275 | 2330 | 5367 | 84.91 | 1.14 | 0.63 | 7.51 | 0.20 | 1.70 | 3.91 |
| 46 | 6 | 137198 | 121721 | 2681 | 1840 | 3479 | 694 | 1784 | 4999 | 88.72 | 1.95 | 1.34 | 2.54 | 0.51 | 1.30 | 3.64 |
| 47 | 7 | 137263 | 121820 | 647 | 6208 | 1143 | 199 | 2746 | 4500 | 88.75 | 0.47 | 4.52 | 0.83 | 0.14 | 2.00 | 3.28 |
| 48 | 8 | 137202 | 113603 | 2047 | 1200 | 4323 | 223 | 10628 | 5178 | 82.80 | 1.49 | 0.87 | 3.15 | 0.16 | 7.75 | 3.77 |
| 49 | 9 | 137223 | 111742 | 1745 | 1362 | 4901 | 210 | 12888 | 4375 | 81.43 | 1.27 | 0.99 | 3.57 | 0.15 | 9.39 | 3.19 |
"""Merging EV and Legislative District datasets"""
ev_leg = pd.merge(ev, subset, on='Legislative District')
ev_leg
| VIN (1-10) | County | City | State | Postal Code | Model Year | Make | Model | Electric Vehicle Type | Clean Alternative Fuel Vehicle (CAFV) Eligibility | ... | Native Hawaiian and Other Pacific Islander Alone 2010 | Some Other Race Alone 2010 | Population of Two or More Races 2010 | White Alone 2010 Percentage | Black or African American Alone 2010 Percentage | American Indian and Alaska Native Alone 2010 Percentage | Asian Alone 2010 Percentage | Native Hawaiian and Other Pacific Islander Alone 2010 Percentage | Some Other Race Alone 2010 Percentage | Population of Two or More Races 2010 Percentage | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 3C3CFFGE4E | Yakima | Yakima | WA | 98902.0 | 2014 | FIAT | 500 | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 133 | 20918 | 5155 | 73.68 | 1.03 | 4.88 | 1.31 | 0.10 | 15.24 | 3.76 |
| 1 | 5YJ3E1EA5L | Yakima | Yakima | WA | 98902.0 | 2020 | TESLA | MODEL 3 | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 133 | 20918 | 5155 | 73.68 | 1.03 | 4.88 | 1.31 | 0.10 | 15.24 | 3.76 |
| 2 | JA4T5VA98P | Yakima | Yakima | WA | 98908.0 | 2023 | MITSUBISHI | OUTLANDER | Plug-in Hybrid Electric Vehicle (PHEV) | Clean Alternative Fuel Vehicle Eligible | ... | 133 | 20918 | 5155 | 73.68 | 1.03 | 4.88 | 1.31 | 0.10 | 15.24 | 3.76 |
| 3 | 5YJ3E1EA7K | Yakima | Tieton | WA | 98947.0 | 2019 | TESLA | MODEL 3 | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 133 | 20918 | 5155 | 73.68 | 1.03 | 4.88 | 1.31 | 0.10 | 15.24 | 3.76 |
| 4 | 1C4JJXR64N | Yakima | Naches | WA | 98937.0 | 2022 | JEEP | WRANGLER | Plug-in Hybrid Electric Vehicle (PHEV) | Not eligible due to low battery range | ... | 133 | 20918 | 5155 | 73.68 | 1.03 | 4.88 | 1.31 | 0.10 | 15.24 | 3.76 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 166430 | KNDC3DLC2P | Whatcom | Bellingham | WA | 98225.0 | 2023 | KIA | EV6 | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | ... | 367 | 5573 | 4953 | 83.97 | 0.87 | 3.72 | 3.50 | 0.27 | 4.06 | 3.61 |
| 166431 | 1N4AZ1CP6J | Whatcom | Ferndale | WA | 98248.0 | 2018 | NISSAN | LEAF | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 367 | 5573 | 4953 | 83.97 | 0.87 | 3.72 | 3.50 | 0.27 | 4.06 | 3.61 |
| 166432 | KM8K33AG8L | Whatcom | Bellingham | WA | 98226.0 | 2020 | HYUNDAI | KONA | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 367 | 5573 | 4953 | 83.97 | 0.87 | 3.72 | 3.50 | 0.27 | 4.06 | 3.61 |
| 166433 | 7SAXCAE56P | Whatcom | Blaine | WA | 98230.0 | 2023 | TESLA | MODEL X | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | ... | 367 | 5573 | 4953 | 83.97 | 0.87 | 3.72 | 3.50 | 0.27 | 4.06 | 3.61 |
| 166434 | 1C4RJXN60R | Whatcom | Bellingham | WA | 98225.0 | 2024 | JEEP | WRANGLER | Plug-in Hybrid Electric Vehicle (PHEV) | Not eligible due to low battery range | ... | 367 | 5573 | 4953 | 83.97 | 0.87 | 3.72 | 3.50 | 0.27 | 4.06 | 3.61 |
166435 rows × 33 columns
def merge_data(csv1_path, csv2_path):
ev_data = pd.read_csv(csv1_path)
racial_data = pd.read_csv(csv2_path)
ev_racial_data = ev_data.merge(racial_data, how="left", left_on="Legislative District", right_on="Legislative District")
ev_racial_data = ev_racial_data.drop(["Unnamed: 0_x", "Unnamed: 0_y"], axis=1) # noticed the merge automatically includes
# these columns so we need to remove them
return ev_racial_data
ev_racial_data = merge_data("Clean_EV_Population.csv", "Clean_Legislative.csv")
display(ev_racial_data)
assert type(ev_racial_data) == pd.DataFrame
assert list(ev_racial_data.columns) == ['VIN (1-10)', 'County', 'City', 'State', 'Postal Code', 'Model Year',
'Make', 'Model', 'Electric Vehicle Type',
'Clean Alternative Fuel Vehicle (CAFV) Eligibility', 'Electric Range',
'Base MSRP', 'Legislative District', 'DOL Vehicle ID',
'Vehicle Location', 'Electric Utility', '2020 Census Tract', 'geometry',
'Total Population 2010', 'Population of One Race 2010',
'White Alone 2010', 'Black or African American Alone 2010',
'American Indian and Alaska Native Alone 2010', 'Asian Alone 2010',
'Native Hawaiian and Other Pacific Islander Alone 2010',
'Some Other Race Alone 2010', 'Population of Two or More Races 2010',
'Hispanic or Latino (of Any Race) 2010', 'Not Hispanic or Latino 2010',
'Population of One Race Not Hispanic or Latino 2010',
'White Alone Not Hispanic or Latino 2010',
'Black or African American Alone Not Hispanic or Latino 2010',
'American Indian and Alaska Native Alone Not Hispanic or Latino 2010',
'Asian Alone Not Hispanic or Latino 2010',
'Native Hawaiian and Other Pacific Islander Alone Not Hispanic or Latino 2010',
'Some Other Race Alone Not Hispanic or Latino 2010',
'Population of Two or More Races Not Hispanic or Latino 2010',
'Total Population Over 18 2010', 'Population of One Race Over 18 2010',
'White Alone Over 18 2010',
'Black or African American Alone Over 18 2010',
'American Indian and Alaska Native Alone Over 18 2010',
'Asian Alone Over 18 2010',
'Native Hawaiian and Other Pacific Islander Alone Over 18 2010',
'Some Other Race Alone Over 18 2010',
'Population of Two or More Races Over 18 2010',
'Hispanic or Latino (of Any Race) Over 18 2010',
'Not Hispanic or Latino Over 18 2010',
'Population of One Race Not Hispanic or Latino Over 18 2010',
'White Alone Not Hispanic or Latino Over 18 2010',
'Black or African American Alone Not Hispanic or Latino Over 18 2010',
'American Indian and Alaska Native Alone Not Hispanic or Latino Over 18 2010',
'Asian Alone Not Hispanic or Latino Over 18 2010',
'Native Hawaiian and Other Pacific Islander Alone Not Hispanic or Latino Over 18 2010',
'Some Other Race Alone Not Hispanic or Latino Over 18 2010',
'Population of Two or More Races Not Hispanic or Latino Over 18 2010'
]
assert len(ev_racial_data) == 166790
| VIN (1-10) | County | City | State | Postal Code | Model Year | Make | Model | Electric Vehicle Type | Clean Alternative Fuel Vehicle (CAFV) Eligibility | ... | Hispanic or Latino (of Any Race) Over 18 2010 | Not Hispanic or Latino Over 18 2010 | Population of One Race Not Hispanic or Latino Over 18 2010 | White Alone Not Hispanic or Latino Over 18 2010 | Black or African American Alone Not Hispanic or Latino Over 18 2010 | American Indian and Alaska Native Alone Not Hispanic or Latino Over 18 2010 | Asian Alone Not Hispanic or Latino Over 18 2010 | Native Hawaiian and Other Pacific Islander Alone Not Hispanic or Latino Over 18 2010 | Some Other Race Alone Not Hispanic or Latino Over 18 2010 | Population of Two or More Races Not Hispanic or Latino Over 18 2010 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 3C3CFFGE4E | Yakima | Yakima | WA | 98902.0 | 2014 | FIAT | 500 | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 21616 | 79487 | 77744 | 71356 | 907 | 3979 | 1312 | 85 | 105 | 1743 |
| 1 | 5YJXCBE40H | Thurston | Olympia | WA | 98513.0 | 2017 | TESLA | MODEL X | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 6102 | 93558 | 90163 | 79905 | 3364 | 1366 | 4367 | 1002 | 159 | 3395 |
| 2 | 3MW39FS03P | King | Renton | WA | 98058.0 | 2023 | BMW | 330E | Plug-in Hybrid Electric Vehicle (PHEV) | Not eligible due to low battery range | ... | 11908 | 92174 | 88859 | 53220 | 10828 | 621 | 23089 | 944 | 157 | 3315 |
| 3 | 7PDSGABA8P | Snohomish | Bothell | WA | 98012.0 | 2023 | RIVIAN | R1S | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | ... | 8755 | 96811 | 94026 | 74239 | 3605 | 738 | 14743 | 548 | 153 | 2785 |
| 4 | 5YJ3E1EB8L | King | Kent | WA | 98031.0 | 2020 | TESLA | MODEL 3 | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 15898 | 89387 | 86183 | 58131 | 10853 | 1010 | 13708 | 2256 | 225 | 3204 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 166785 | 3FA6P0SU4D | Spokane | Spokane | WA | 99223.0 | 2013 | FORD | FUSION | Plug-in Hybrid Electric Vehicle (PHEV) | Not eligible due to low battery range | ... | 4280 | 102421 | 100196 | 93650 | 2031 | 1227 | 2748 | 431 | 109 | 2225 |
| 166786 | 5YJYGDEE5M | King | Sammamish | WA | 98074.0 | 2021 | TESLA | MODEL Y | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | ... | 5316 | 96646 | 94492 | 79983 | 1214 | 331 | 12492 | 144 | 328 | 2154 |
| 166787 | 7SAYGDEE5N | Snohomish | Mukilteo | WA | 98275.0 | 2022 | TESLA | MODEL Y | Battery Electric Vehicle (BEV) | Eligibility unknown as battery range has not b... | ... | 8755 | 96811 | 94026 | 74239 | 3605 | 738 | 14743 | 548 | 153 | 2785 |
| 166788 | 1G1RH6E43D | Lewis | Mossyrock | WA | 98564.0 | 2013 | CHEVROLET | VOLT | Plug-in Hybrid Electric Vehicle (PHEV) | Clean Alternative Fuel Vehicle Eligible | ... | 5858 | 98475 | 96452 | 93519 | 467 | 1305 | 918 | 166 | 77 | 2023 |
| 166789 | 5YJSA1E27H | Pierce | Gig Harbor | WA | 98332.0 | 2017 | TESLA | MODEL S | Battery Electric Vehicle (BEV) | Clean Alternative Fuel Vehicle Eligible | ... | 4927 | 101989 | 98964 | 91180 | 2367 | 1046 | 3480 | 758 | 133 | 3025 |
166790 rows × 56 columns
Results¶
In terms of the first and second research questions, we can see that accessibility to charging stations in rural areas, especially Eastern WA, is an issue. In the urban areas, otherwise known as very populated regions, there is a surplus of charging stations. However, when you look at other regions, like the lower left corner of the state or the middle or eastern side of the state, you can see a lack of charging infrastructure. From the interactive plotly map of Washington State shown below, the blue dots represent the electric vehicles in Washington state, while the red dots represent the charging station locations. One surprising takeaway from the map is that accessibility does not seem to be a deterrent in purchasing and owning electric vehicles because if it was, there would not be blue dots where there are no red dots. Regarding the fourth research question, you can see that there are clusters of electric vehicle adoption in urban areas especially, like the greater Seattle area cities, but there is also adoption of electric vehicles all over the state. Relative to charging stations, this is not a big deal as described above, which means there are most likely many electric vehicle owners with access to private charging stations.
geometry1 = ev_racial_data["Vehicle Location"].apply(wkt.loads)
ev_racial_gdf = gpd.GeoDataFrame(ev_racial_data, geometry=geometry1, crs="EPSG:4326")
geometry2 = [Point(xy) for xy in zip(charging_df["Longitude"], charging_df["Latitude"])]
charging_gdf = gpd.GeoDataFrame(charging_df, geometry=geometry2, crs="EPSG:4326")
# Set CRS for GeoDataFrames to EPSG:4326
state_data.crs = 'EPSG:4326'
entire_state = state_data[["geometry"]].dissolve()
fig, ax = plt.subplots(figsize=(10, 5))
entire_state.plot(ax=ax, color="#EEE")
state_data.plot(ax=ax, facecolor="#CCCCCC" , edgecolor="black")
# Plot EV ownership
wa_data = gpd.sjoin(ev_racial_gdf, state_data, how='inner', predicate='intersects')
wa_data.plot(ax=ax, color="blue", marker="o", markersize=1, label="EV Ownership")
# Plot EV charging stations
charging_gdf.plot(ax=ax, color="red", marker="o", markersize=1, label="EV Charging Stations")
# Set title and turn off axis
ax.set_title("Washington with EV Charging Stations & EV Ownership")
ax.set_axis_off()
ax.legend()
plt.show()
assert type(ev_racial_gdf) == gpd.GeoDataFrame
assert type(charging_gdf) == gpd.GeoDataFrame
assert ax.get_title() == "Washington with EV Charging Stations & EV Ownership", "title does not match expected"
assert not ax.axison, "borders and labels must be hidden"
assert ax.legend() is not None, "missing legend"
# Perform spatial join between ev_racial_gdf and state_data
wa_data = gpd.sjoin(ev_racial_gdf, state_data, how='inner', predicate='intersects')
# Plot EV charging stations and EV ownership using Plotly Express
fig = px.scatter_mapbox(charging_gdf,
lat="Latitude",
lon="Longitude",
color_discrete_sequence=["red"],
hover_name="Station Name",
mapbox_style="carto-positron",
zoom=5,
opacity=0.7,
title="Washington with EV Charging Stations & EV Ownership")
fig.add_scattermapbox(lat=wa_data.geometry.y,
lon=wa_data.geometry.x,
mode="markers",
marker=dict(color="blue", size=4),
hoverinfo="text",
text="EV Home",
name="EV Ownership")
# Using renderer to display interactive map in Jupyter Notebook
fig.show(renderer='iframe')
# Show the interactive map
fig.show()
One of the research questions that we wanted to address was “Is there a racial disparity in access to electric vehicles in Washington?” We first investigated this by creating a scatter plot that compares the percentage of white individuals within a legislative district to the percentage of EVs in a legislative district out of all the EVs registered in Washington. Overall, there was not a significant relationship between the two variables, but there did appear to be a slight positive correlation. For example, Legislative District 15, which includes portions of Adams, Benton, Franklin, Grant, and Yakima counties in southern Washington, is 60% white and makes up only 0.2% of all EVs in the state, while Legislative District 5, which includes portions of Kittias, Maple Valley, Renton, Issaquah, and Snohomish counties in central Washington, is 85% white and makes up 4% of all EVs in the state. This is a significantly higher percentage of EV ownership with a higher proportion of white individuals. From these results, we can conclude that race may be a limiting factor in access to electric vehicle ownership. Yakima County, for example, located in Legislative District 15, is Washington State’s largest majority-Hispanic county, as of 2020 (Wikipedia). Due to systematic housing discrimination, people of color experience lower rates of homeownership and lower average income, which limits access to electric vehicles. This is due to the cost of buying and maintaining an electric vehicle, which already has a higher upfront cost than gas-powered vehicles, and due to the limited public charging infrastructure available, especially in less-developed areas. However, it is important to note that race is not the only factor that impacts access to EVs. As shown in the scatterplot, many legislative districts displayed are over 85% white and have similar EV ownership rates to legislative districts with a lower white population. This highlights that other factors come into play when addressing the lack of electric vehicle adoption today, including the lack of robust charging infrastructure and consumers’ views on affordability and EV performance.
"""Interactive scatterplot comparing the percentage of white individuals (x) to the percentage of EV ownership in each
legislative district in WA"""
# Uses the plotlyexpress library to create the scatterplot
interactive = px.scatter(ev_leg, x='White Alone 2010 Percentage', y='Percentage EV Ownership', hover_data=['Legislative District'])
interactive.update_layout(title='Percentage of White Individuals vs Percentage of EV Ownership per WA Legislative District',
xaxis_title='Percentage of White Individuals',
yaxis_title='Percentage of EV Ownership')
# Using renderer to display interactive graph in Jupyter Notebook
interactive.show(renderer='iframe')
interactive.show()
To further explore the question of whether there is a racial disparity in access to electric vehicles in Washington, we also created two bar plots that compared the racial distribution of the legislative districts with the highest and lowest EV ownership in Washington. The results are not drastically different, as in both legislative districts, the population is majority white. However, an interesting result from the bar plot showing Legislative District 15, which has the lowest percentage of EV ownership, was that over 30% of the population identified themselves as “Some Other Race.” The United States Census Bureau analyzed what the most common groups were that identified themselves as this in the racial category, and they concluded that the top 3 most common groups were Brazilians, Guyanese, and Cabo Verdeans. Additionally, a large majority of census respondents who selected “Some Other Race” identified as Hispanic when asked to disclose their ethnicity. This aligns with the fact that Yakima County, which as mentioned before is within Legislative District 15, is the largest majority-Hispanic county in Washington. It is meaningful to note that the legislative district with the lowest EV ownership in the state has a sizable proportion of people of color, specifically Hispanic or Latino individuals, which further supports the idea that communities of color may face a greater lack of access to electric vehicles than a community that is predominantly white, such as one found in Legislative District 41. Legislative District 41 includes Mercer Island, Newcastle, Bellevue, Renton, Issaquah, and Sammamish. Bellevue, for example, is a tech company hub and includes suburbs of higher socioeconomic status and predominantly white communities. Electric vehicles appear to be more available in places like Bellevue, where affordability and accessibility may be more feasible. Overall, while there wasn’t a strong relationship between race and EV ownership shown by the visualizations we created, it is important to note how race can be a factor in accessibility of electric vehicles.
"""Barplots showing racial distribution of legislative districts with highest and lowest percent EV ownership"""
# Locates the row with the highest and lowest percent EV ownership
high_ev_index = ev_leg['Percentage EV Ownership'].idxmax()
high_ev_district = ev_leg.loc[high_ev_index]
low_ev_index = ev_leg['Percentage EV Ownership'].idxmin()
low_ev_district = ev_leg.loc[low_ev_index]
# Creating dictionaries with the columns used to make the barplots
high_ev_data = {'Legislative District': high_ev_district['Legislative District'], 'Race': ['White', 'Black', 'Asian', 'Two or More Races', 'Some Other Race'],
'Percentage': [high_ev_district['White Alone 2010 Percentage'], high_ev_district['Black or African American Alone 2010 Percentage'],
high_ev_district['Asian Alone 2010 Percentage'], high_ev_district['Population of Two or More Races 2010 Percentage'],
high_ev_district['Some Other Race Alone 2010 Percentage']]}
low_ev_data = {'Legislative District': low_ev_district['Legislative District'], 'Race': ['White', 'Black', 'Asian', 'Two or More Races', 'Some Other Race'],
'Percentage': [low_ev_district['White Alone 2010 Percentage'], low_ev_district['Black or African American Alone 2010 Percentage'],
low_ev_district['Asian Alone 2010 Percentage'], low_ev_district['Population of Two or More Races 2010 Percentage'],
low_ev_district['Some Other Race Alone 2010 Percentage']]}
# Converting the dictionaries into dataframes
high_ev_df = pd.DataFrame(high_ev_data)
low_ev_df = pd.DataFrame(low_ev_data)
# Creating the highest EV ownership race distribution barplot
sns.set(style='white')
sns.set_palette('Set2')
high_barplot = sns.catplot(data=high_ev_df, x='Legislative District', y='Percentage', hue='Race', kind='bar')
plt.xlabel('Legislative District 41')
plt.ylabel('Percentage of Race')
plt.title('Race Dist. of Legislative District with the Highest EV Ownership in WA')
# Making sure that the y-axes on both graphs are equal
plt.ylim(0, max(high_ev_df['Percentage']))
plt.show()
# Creating the lowest EV ownership race distribution barplot
sns.set(style='white')
sns.set_palette('Set2')
low_barplot = sns.catplot(data=low_ev_df, x='Legislative District', y='Percentage', hue='Race', kind='bar')
plt.xlabel('Legislative District 15')
plt.ylabel('Percentage of Race')
plt.title('Race Dist. of Legislative District with the Lowest EV Ownership in WA')
# Making sure that the y-axes on both graphs are equal
plt.ylim(0, max(high_ev_df['Percentage']))
plt.show()
Impact and Limitations¶
On a more general level, from this report we may be assuming that everyone understands the definition of an electric vehicle and what qualifies to be an electric vehicle. Although this may seem ridiculous, electric vehicles are newer and still developing which makes it difficult to form a solid way to categorize and define them.
There are many different ways to apply these findings such as policy creation, environmental impacts, and economical decisions. For example, these findings could be useful for policymakers about where Washington state is at in terms of electric vehicle adoption and availability or accessibility of charging stations for the owners. This could influence investments made by the city or the local government on whether or not they should build more charging infrastructure based on the demand. In terms of environment, understanding the distribution of electric vehicles across different regions of Washington state can shed light on the potential greenhouse gas emissions reduction and air pollution. To transition, this could be helpful for anyone who may seem to raise an eyebrow at the importance of sustainability, like big companies who are actually trying to make a positive impact on the environment and are not just greenwashing. Any companies involved in the electric vehicle industry could benefit with insights into market demand for electric vehicles or chargers as well as identifying opportunities for growth and further investment.
Climate change and the effects of it are a collective issue. However, it is important to highlight how certain groups, based on discriminative history, feel these impacts much greater than others. By first diving into the idea of a racial disparity in access to electric vehicles, we are able to communicate an issue of environmental injustice. Communities deserve equitable access to sustainable practices, such as purchasing an electric vehicle. Many blame those who still use gas-fueled vehicles as careless towards the environment, but it is important to highlight the inaccessibility of electric vehicles for some groups. Research like this can serve as a basis for building federal policy and incentive which achieves equitable access for all. As with any topic regarding environmental justice, it is important to get involved with these communities to hear their own views on electric vehicle access. While data can begin to tell the story of injustice, the story is not fully told until the ones experiencing the injustice are heard and uplifted. It may harm these communities to, for example, release this data claiming there is a racial disparity, all while ignoring how people of color really feel about these issues. It’s important to highlight that there were significant limitations with our data setting. For example, the 2010 Census Data by Legislative District is 14 years old, and population distributions have likely changed significantly. Trying to compare this data to the electric vehicle dataset, which is present day data, can be inaccurate and lead to conclusions that do not represent the state of electric vehicle adoption and racial distribution today. Additionally, the visualizations created to dive into the topic of racial disparity in access to electric vehicles did not have very obvious conclusions. While we claim here that a disparity may exist, it’s important to understand that the analysis does not claim a tight relationship between the two variables. Even so, we still believe it is important to highlight how a sustainable practice hailed by many, such as electric vehicles, can uncover issues of equity and discrimination. Other maybe more minor limitations from our data include the accuracy and completeness of the data, since some of the data may not be completely up to date regarding both the electric vehicle populations and newly developed charging stations. In order to use this report to make informed decisions, we may need to find a very recently updated dataset with electric vehicles and charging stations that is updated on a monthly basis.
Challenge Goals¶
Multiple datasets: In our code, we use three different datasets: current registered electric vehicles in Washington, racial demographics in 2010 by Legislative District, and current electric vehicle charging stations in Washington state. We merged the electric vehicles and Legislative District datasets on the Legislative District column and used the geometries of the electric vehicle locations and charging station datasets to create maps of Washington state. This challenge goal was a bit difficult to achieve, especially the part where all three datasets needed to be used together in some way. These datasets were not perfectly cohesive with each other and therefore made them difficult to work with together, but Sophia was able to create a map that incorporates all three datasets to convey EV and charging station distribution, and then being able to identify the legislative district by color.
New library: Our project meets this goal because we used Plotly to make an interactive scatterplot (i.e., being able to hover the cursor over a point and see location). We focused on learning an interactive visualization library on a scatterplot rather than a map like we originally planned because it seemed more feasible in our time frame and the learning curve of using Plotly Express was pretty straightforward and felt similar to graphing with seaborn or matplotlib.
Plan Evaluation¶
In the team project proposal, our written plan was not too detailed, but after meeting with our assigned mentor, he suggested that we sit down and make a rough timeline of when we want to complete each of the steps we had listed. Our expectations for completing the data organizing and data cleaning was only a day or two, which was what we found to be very doable. Looking back, I would say we did accomplish some other data cleaning tasks throughout the completion of the code, as the more we worked with the datasets, the easier it was to discover certain changes and cleaning steps necessary. The next step listed, merging the datasets, took much longer than we thought it would. When merging the legislation dataset containing all of the racial demographic information and the electric vehicle population dataset, it was difficult to merge them on the Legislative District column. The electric vehicle population dataset’s column named “Legislative District” was a float type, while the racial demographic dataset’s issue was that the Legislative Districts 1 through 9 (single digits) had a leading 0 in front of the number to make them 2 digits instead of one which needed to be removed. Additionally, for the maps created of Washington state, we took the state dataset given to us in the Mapping Assessment to map the background of Washington state along with its census tracts to help get a better understanding and perspective on the areas in the state relative to where the electric vehicle ownership is and relative to where the EV charging stations are located. However, this portion of the project and code was one of the lengthiest and most time consuming. We made attempts at a folium map, but it only “ran” once before crashing the Jupyter notebook and Google Colab so we decided to scratch it and use solely the plotly. Constantly, we were frustrated with errors and discovered that there were issues with the geometry columns in the datasets not actually representing geometries and instead were object types or floats. Therefore, we had to change the types of the columns as well as make the charging station dataset and merged dataset, containing the information on electric vehicles and racial demographics, into a geodataframe. After resolving the issues of the geometry columns, we were able to map everything. Later on, we decided to perform some calculations on percentages (such as the racial demographics and the percentage of EV ownership) as a lot of the data was raw population numbers or difficult to interpret from the original dataset, so calculating percentages seemed to be a lot more helpful for interpreting results and making visualizations. This required doing simple percentage calculations and then creating columns to then merge onto the main dataset we were working on for data analysis.
Testing¶
Calculations were performed to see the percentage of EV ownership and the racial distributions in the census data. In order to test that these calculations were correct, assert statements were used. We created an ‘expected output’ dataframe based on a small subset of the rates dataframe (which calculated the percentage of EV ownership) and the subset data frame (which calculated the racial distributions), and then hand-calculated the percentages. We then used the pandas function ‘.equals’ to assert that a subset of the two data frames mentioned matched our hand-calculations. For the merging of the datasets function, we were able to set up test assertions for inclusion of all correct columns by using the df.columns for each individual dataset. Then, the length assertion would be for the number of rows and just a simple initial assert ensuring that the dataframe imported was a pandas dataframe. For the mapping, we decided to use some of the testing that was given to us in the Mapping Assessment. Here, we tested for correct title names, presence of a legend, missing borders and labels. Also, we tested the GeoDataFrames that were created in spite of the mapping to ensure that they were GeoDataFrames.
Collaboration¶
Besides our peers and helpful teaching staff, the majority of our mapping section was completed thanks to the already completed mapping assessment we turned in a few weeks ago. Using some of the sources for importing the state data and the coding chunks used to sort the data just for Washington state, we were able to include this basic background or outline of the state and its census tracts in our own creation of maps for the electric vehicles and charging stations. We used generative AI in some portions of the mapping for miniscule tasks like changing map fill color and changing the marker size in the plot. Generative AI was also used to resolve some crazy unknown key errors or type errors that a simple Google search could not resolve for us. Some other resources that were available to our group was the help of using plotly in R Studio for one of our group members' informatics class. Although the coding lines look different in Python than R Studio, it was easier to understand and develop the plotly interactive map having used it all quarter in another class. Generative AI was also helpful for little issues we were running into with the merging of the census and EV data. For example, we kept running into an error when calculating the percentage of EV ownership where duplicate columns would be made which caused a merge error down the line when edits were made. We prompted Generative AI with the error which suggested using an if statement to drop the duplicate column if it is detected in the dataset, which solved the problem. Another way Generative AI was helpful was in fixing the barplot visualization for the racial distribution. We wanted the y-axes to have the same range to avoid a misleading visualization, and Generative AI suggested using the function ylim, which we read the documentation for in order to understand how it worked. Additionally, referring to the documentation for libraries like pandas, seaborn, and plotly was incredibly helpful in figuring out what certain functions would be helpful when merging datasets.